#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include<functional>
#include <sys/epoll.h>
#include "err.hpp"
#include "log.hpp"
#include "sock.hpp"

namespace epoll_ns
{
    static const uint16_t defaultport = 8888;
    static const int size = 128;
    static const int defaultval = -1;
    static const int defaultnum = 64;

    using func_t = std::function<std::string(const std::string&)>;

    class EpollServer
    {
    public:
        EpollServer(func_t f,int num = defaultnum, uint16_t port = defaultport)
            :_func(f), _num(num), _revs(nullptr), _port(port), _listensock(defaultval), _epfd(defaultval)
        {
        }
        void initServer()
        {
            // 1.创建socket
            _listensock = Sock::Socket();
            Sock::Bind(_listensock, _port);
            Sock::Listen(_listensock);
            // 2.创建epoll模型
            _epfd = epoll_create(size);
            if (_epfd < 0)
            {
                logMessage(FATAL, "epoll create error: %s", strerror(errno));
                exit(EPOLL_CREATE_ERR);
            }
            // 3.添加listensock到epoll中！
            struct epoll_event ev;
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = _listensock; // 当事件就绪，被重新捞取上来的时候，我要知道是哪一个fd就绪了！
            epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &ev);
            // 4.申请就绪事件的空间
            _revs = new struct epoll_event[_num];

            logMessage(NOMAL, "init server success");
        }
        void HandlerEvent(int readMax)
        {
            logMessage(DEBUG, "HandlerEvent in");
            for (int i = 0; i < readMax; i++)
            {
                uint32_t evevts = _revs[i].events;
                int sock = _revs[i].data.fd;

                if (sock == _listensock && (evevts == EPOLLIN))
                {
                    // _listensock读事件就绪了，获取新连接
                    std::string clientip;
                    uint16_t clientport;
                    int fd = Sock::Accept(sock, &clientip, &clientport);
                    if (fd < 0)
                    {
                        logMessage(WARING, "accept err");
                        continue;
                    }
                    // 获取fd成功，不能直接读取，放入epoll
                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = fd;
                    epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
                    logMessage(NOMAL,"accept a new link success ,get new sock: %d",fd);
                }
                else if ((evevts == EPOLLIN))
                {
                    // 普通的读事件就绪
                    // 依旧有问题，没保证完整读取，打循环也有问题，又会被阻塞
                    char buffer[1024];
                    // 把本轮的数据读完了，就一定能够读完一个完整的请求吗？？不能！
                    int n = recv(sock, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        logMessage(DEBUG, "client# %s", buffer);
                        // TODO
                        std::string response = _func(buffer);

                        send(sock,response.c_str(),response.size(),0);
                    }
                    else if (n == 0)
                    {
                        // 因为底层是红黑树，直接用sock作为key，就可以删除节点，我也并不需要关心event
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        // 建议先从epoll移除，才close fd。因为要保证sock是一个合法的sock
                        close(sock);
                        logMessage(NOMAL, "client quit");
                    }
                    else
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(ERROR, "recv error,code: %d,errstring: %s",errno,strerror(errno));
                    }
                }
                else
                {
                }
            }
            logMessage(DEBUG, "HandlerEvent out");
        }
        void start()
        {
            int timeout = -1;
            for (;;)
            {
                int n = epoll_wait(_epfd, _revs, _num, timeout);
                switch (n)
                {
                case 0:
                    logMessage(NOMAL, "timeout...");
                    break;
                case -1:
                    logMessage(WARING, "epoll error,code: %d,err string: %s", errno, strerror(errno));
                    break;
                default:
                {
                    logMessage(NOMAL, "have event read!");
                    // HandlerEvent(n); // 传入n，让我知道有几个事件就绪了
                }
                break;
                }
            }
        }
        ~EpollServer()
        {
            if (_listensock != defaultval)
                close(_listensock);
            if (_epfd != defaultval)
                close(_epfd);
            if (_revs)
                delete[] _revs;
        }

    private:
        uint16_t _port;
        int _listensock;
        int _epfd; // epoll模型 ， 底层跟file struct file是一个原理
        struct epoll_event *_revs;
        int _num;
        func_t _func;
    };
}